/* ---------------------------------------------Marlin Toolkit----------------------------------------*
Authors : Daniel Randle, Alex Bourne
Date Created : Mar 1 2013

File:
mapwindow.cpp

Description:
This file contains the definition for the MapWindow class functions along with any
helper functions associated with the class
*-----------------------------------------------------------------------------------------------------*/

// Includes
#include <mapwindow.h>
#include <nsshader.h>
#include <nsmesh.h>
#include <nsobject.h>
#include <nsobjectreference.h>
#include <nsobjectreferenceset.h>
#include <nslight.h>
#include <nsshaderset.h>
#include <nsobjectset.h>
#include <inputmapping.h>
#include <sstream>
#include <nscamera.h>
#include <nsengine.h>
#include <mainwindow.h>
#include <nshextile.h>
#include <qstring.h>


#ifdef DEBUG
#include <debug.h>
#endif

// Qt Includes
#include <qevent.h>
#include <qtimer.h>
#include <qapplication.h>
#include <qdesktopwidget.h>

namespace ToolkitGui
{
/*---------------------------*
|   class MapWindow BEGINS  |
*---------------------------*/


/* Constructor
Description:
	Create and initialize all parts the map window. This includes calling the parent contructor.

Parameters:
	parent : The parent of this window - most likely the MainWindow object
	shareWidget : Any QGLWidgets that share OpenGL display lists and texture objects. Possibly
					the views showing tile sets and entities.
	f : The window flags - carry through so that any style of window flags in a parent window
		will propagate through (ie no x or no title bar)

Return:
	None
*/
MapWindow::MapWindow(const QGLFormat & form, QWidget * parent, MainWindow * mainWin, const QGLWidget * shareWidget, Qt::WindowFlags f):
	QGLWidget(form, parent,shareWidget,f),
	mainWindow(mainWin),
	inputMap(NULL),
	guiUpdate(true) // we want to post update once on startup
{
	#ifdef DEBUG
	d = NULL;
	#endif
	_initObjects();
	_setupUi();
	_setupConnections();
	setMouseTracking(true);
}

MapWindow::~MapWindow()
{
	LogFile("Deleting input map...");
	delete inputMap;
}

/* _initObjects
Description:
	Create and initialize all objects in the map window. This includes the GameMap stuff

Parameters:
	None

Return:
	None
*/
void MapWindow::_initObjects()
{}

/* _setupUI
Description:
	Setup the display of the map editing screen (size and such) including any toolbars and menus.
Parameters:
	None

Return:
	None
*/
void MapWindow::_setupUi()
{
	setFocusPolicy(Qt::StrongFocus);
}

/* _setupUI
Description:
	Setup the display of the map editing screen (size and such)
Parameters:
	None

Return:
	None
*/
void MapWindow::_setupConnections()
{
	QTimer * up = new QTimer();
	connect(up, SIGNAL(timeout()),this, SLOT(OnIdle()));
	up->start(0);
}

void MapWindow::OnIdle()
{
	updateGL();
}

void MapWindow::keyReleaseEvent ( QKeyEvent * keyEvent )
{
	if (!inputMap->onKeyRelease(keyEvent))
		QGLWidget::keyReleaseEvent(keyEvent);
}

void MapWindow::keyPressEvent(QKeyEvent * kEvent)
{
	if (!inputMap->onKeyPress(kEvent))
		return QGLWidget::keyPressEvent(kEvent);
}

void MapWindow::mouseMoveEvent( QMouseEvent * mevent )
{
	inputMap->onMouseMovement(mevent);
}

void MapWindow::mouseReleaseEvent ( QMouseEvent * mevent )
{
	inputMap->onMouseRelease(mevent);
}

void MapWindow::mousePressEvent ( QMouseEvent * mevent )
{
	inputMap->onMousePress(mevent);
}

void MapWindow::mouseDoubleClickEvent ( QMouseEvent * event )
{
	NSMapBuilder * mb = engine->getMapBuilder();
	if (mb->isActivated())
		inputMap->enterBuildMode(false);
}

void MapWindow::wheelEvent ( QWheelEvent * wevent )
{
	inputMap->onMouseWheel(wevent);
}

void MapWindow::initializeGL()
{
	GLenum cont = glewInit();
	LogFile((char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
	if (cont != GLEW_OK)
	{
		LogFile("GLEW extensions unable to initialize");
		exit(1);
	}
    glFrontFace(GL_CW);
	glDepthFunc(GL_LEQUAL);
	glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);

	
	engine = new NSEngine();
	NSCamera * cam = engine->getCamera();
	cam->setTimer(&timer);

	NSHexTile * hexTile = new NSHexTile("GrassTile","DAEgrass.dae","Meshes/Tiles","Textures/Tiles",false);
	NSHexTile * hexTile2 = new NSHexTile("WoodTile","DAEwood.dae","Meshes/Tiles","Textures/Tiles");
	NSHexTile * hexTile3 = new NSHexTile("BrickTile","DAEbrick.dae","Meshes/Tiles","Textures/Tiles");
	NSHexTile * hexTile4 = new NSHexTile("WaterTile","DAEwater.dae","Meshes/Tiles","Textures/Tiles",false,true);
	NSHexTile * hexTile5 = new NSHexTile("SwampTile","DAEswamp.dae","Meshes/Tiles","Textures/Tiles");
	NSHexTile * hexTile6 = new NSHexTile("LavaTile","DAElava.dae","Meshes/Tiles","Textures/Tiles");
	NSHexTile * hexTile7 = new NSHexTile("SandTile","DAEsand.dae","Meshes/Tiles","Textures/Tiles");
	NSHexTile * hexTile12 = new NSHexTile("TestAlpha","DAEtest.dae","Meshes/Tiles","Textures/Tiles");
	NSHexTile * hexTile8 = new NSHexTile("StoneTile","DAEstone.dae","Meshes/Tiles","Textures/Tiles");
	NSHexTile * hexTile9 = new NSHexTile("CobblestoneTile","DAEcobblestone.dae","Meshes/Tiles","Textures/Tiles");
	NSHexTile * hexTile10 = new NSHexTile("SnowTile","DAEsnow.dae","Meshes/Tiles","Textures/Tiles");
	NSHexTile * hexTile11 = new NSHexTile("IceTile","DAEalphatest.dae","Meshes/Tiles","Textures/Tiles");
	NSObject * dbDown = new NSObject("DrawBridgeDown","DAEdbdown.dae","Meshes/Landscape","Textures/Landscape",true);
	NSObject * dbUp = new NSObject("DrawBridgeUp","DAEdbup.dae","Meshes/Landscape","Textures/Landscape",true);
	NSObject * dbFrame = new NSObject("DrawBridgeFrame","DAEdbframe.dae","Meshes/Landscape","Textures/Landscape",true);
	NSObject * tree1 = new NSObject("LeafTree","DAEleaftree.dae","Meshes/Landscape","Textures/Landscape",true);
	NSObject * tree2 = new NSObject("PineTree1","DAEpinetree.dae","Meshes/Landscape","Textures/Landscape",true);
	NSObject * tree3 = new NSObject("PineTree2","DAEpinetree2.dae","Meshes/Landscape","Textures/Landscape",true);
	NSObject * tree4 = new NSObject("PineTree3","DAEpinetree3.dae","Meshes/Landscape","Textures/Landscape",true);
	NSObject * door1 = new NSObject("Door","DAEdoor.dae","Meshes/Landscape","Textures/Landscape",true);
	NSObject * door2 = new NSObject("DoorFrame","DAEdoorframe.dae","Meshes/Landscape","Textures/Landscape",true);
	NSObject * dd = new NSObject("Hawkgirl","Hawkgirl_V.dae","Meshes/Characters","Textures/Characters",true);


	NSPointLight * light = new NSPointLight("PointLight","pointlight.dae","Meshes/Lights","Textures/Landscape",1.0f,0.4f,0.0f,7.0f,6.0f);
	NSSpotLight * light2 = new NSSpotLight("SpotLight","spotlight.dae","Meshes/Lights","Textures/Landscape",60.0f,1.0f,0.3f,0.0f,7.0f,1.5f,16.0f,2.0,NSVec3Df(1.0f,1.0f,1.0f));
	NSSpotLight * light3 = new NSSpotLight("SpotLight2","spotlight.dae","Meshes/Lights","Textures/Landscape",60.0f,1.0f,0.7f,0.0f,7.0f,0.5f,16.0f,0.5,NSVec3Df(0.0f,1.0f,1.0f));
	NSSpotLight * light4 = new NSSpotLight("SpotLight3","spotlight.dae","Meshes/Lights","Textures/Landscape",60.0f,1.0f,0.7f,0.0f,7.0f,0.5f,16.0f,0.5,NSVec3Df(0.0f,0.0f,1.0f));
	NSSpotLight * light5 = new NSSpotLight("SpotLight4","spotlight.dae","Meshes/Lights","Textures/Landscape",60.0f,1.0f,0.7f,0.0f,7.0f,0.5f,16.0f,0.5,NSVec3Df(1.0f,0.0f,0.0f));
	NSSpotLight * light6 = new NSSpotLight("SpotLight5","spotlight.dae","Meshes/Lights","Textures/Landscape",60.0f,1.0f,0.7f,0.0f,7.0f,0.5f,16.0f,0.5,NSVec3Df(1.0f,1.0f,0.0f));
	NSSpotLight * light7 = new NSSpotLight("SpotLight6","spotlight.dae","Meshes/Lights","Textures/Landscape",60.0f,1.0f,0.7f,0.0f,7.0f,0.5f,16.0f,0.5,NSVec3Df(0.0f,0.0f,1.0f));
	NSSpotLight * light8 = new NSSpotLight("SpotLight7","spotlight.dae","Meshes/Lights","Textures/Landscape",60.0f,1.0f,0.7f,0.0f,7.0f,0.5f,16.0f,0.5,NSVec3Df(1.0f,0.0f,1.0f));

	light->init();
	light2->init();
	light3->init();
	light4->init();
	light5->init();
	light6->init();
	light7->init();
	light8->init();

	NSShader * gShader = engine->getShader("GeometryShader");

	engine->addObject(gShader,hexTile);
	engine->addObject(gShader,hexTile2);
	engine->addObject(gShader,hexTile3);
	engine->addObject(gShader,hexTile4);
	engine->addObject(gShader,hexTile5);
	engine->addObject(gShader,hexTile6);
	engine->addObject(gShader,hexTile7);
	engine->addObject(gShader,hexTile8);
	engine->addObject(gShader,hexTile9);
	engine->addObject(gShader,hexTile10);
	engine->addObject(gShader,hexTile11);
	engine->addObject(gShader,dbDown);
	engine->addObject(gShader,dbUp);
	engine->addObject(gShader,dbFrame);
	engine->addObject(gShader,tree1);
	engine->addObject(gShader,tree2);
	engine->addObject(gShader,tree3);
	engine->addObject(gShader,tree4);
	engine->addObject(gShader,door1);
	engine->addObject(gShader,door2);
	engine->addObject(gShader,dd);
	engine->addObject(gShader,light);
	engine->addObject(gShader,light2);
	engine->addObject(gShader,light3);
	engine->addObject(gShader,light4);
	engine->addObject(gShader,light5);
	engine->addObject(gShader,light6);
	engine->addObject(gShader,light7);
	engine->addObject(gShader,light8);

	for (int z = 2; z < 3; ++z)
	{
		for (int x = 10; x < 50; ++x)
		{
			for (int y = 10; y < 50; ++y)
			{
				float screenX = (0.86f * x * 2.0f);
				float screenY = (1.49f * y );
				if ((y % 2) != 0)
					screenX += 0.86f;
				float screenZ = (float(z)*.45);

				engine->addReference(
					hexTile, NSVec3Df(screenX,screenY,screenZ));
			}
		}
	}

	inputMap = new InputMapping(engine,this);
	inputMap->setDebug(d);
	timer.restart();
	engine->setProjectionMatrix(35.0f,width(),height());
}

void MapWindow::resizeGL(int width, int height)
{
	engine->resize(width, height);
}

void MapWindow::paintGL()
{
	engine->update();
	engine->draw();
	engine->drawOverlays();
	if (guiUpdate)
	{
		mainWindow->myUpdate();
		guiUpdate = false;
	}
}

NSEngine* MapWindow::getEngine()
{
	return engine;
}

void MapWindow::postUpdate()
{
	guiUpdate = true;
}

void MapWindow::onActivateBuild()
{
	setFocus();
	inputMap->enterBuildMode(true);
}

#ifdef DEBUG
void MapWindow::setDebug(Debug * debug)
{
	d = debug;
	inputMap->setDebug(debug);
}
#endif
}